package com.xdog.okx.service.impl;

import com.xdog.okx.service.IWeb3jService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.FunctionReturnDecoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.Utf8String;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.DefaultBlockParameterNumber;
import org.web3j.protocol.core.Request;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.*;
import org.web3j.utils.Numeric;

import java.io.IOException;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Web3j服务实现类
 * 提供基于Web3j的区块链数据查询功能
 */
@Slf4j
@Service
public class Web3jServiceImpl implements IWeb3jService {

    @Resource
    private Web3j web3j;

    @Override
    public EthBlock getBlockByNumber(BigInteger blockNumber) throws IOException {
        return web3j.ethGetBlockByNumber(new DefaultBlockParameterNumber(blockNumber), true).send();
    }

    @Override
    public EthTransaction getTransactionByHash(String transactionHash) throws IOException {
        return web3j.ethGetTransactionByHash(transactionHash).send();
    }

    @Override
    public EthGetBalance getBalance(String address) throws IOException {
        return web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST).send();
    }

    @Override
    public EthGetBlockTransactionCountByNumber getTransactionCountByBlockNumber(BigInteger blockNumber) throws IOException {
        return web3j.ethGetBlockTransactionCountByNumber(new DefaultBlockParameterNumber(blockNumber)).send();
    }

    @Override
    public EthGetTransactionCount getTransactionCountByAddress(String address) throws IOException {
        return web3j.ethGetTransactionCount(address, DefaultBlockParameterName.LATEST).send();
    }
    
    @Override
    public String getTokenName(String tokenAddress) throws Exception {
        // ERC20 name() 函数调用
        Function function = new Function(
                "name",
                Collections.emptyList(),
                Arrays.asList(new TypeReference<Utf8String>() {})
        );
        
        String encodedFunction = FunctionEncoder.encode(function);
        EthCall response = web3j.ethCall(
                Transaction.createEthCallTransaction(null, tokenAddress, encodedFunction),
                DefaultBlockParameterName.LATEST)
                .send();
        
        List<Type> result = FunctionReturnDecoder.decode(
                response.getValue(), function.getOutputParameters());
        
        return result.isEmpty() ? "" : ((Utf8String) result.get(0)).getValue();
    }
    
    @Override
    public String getTokenSymbol(String tokenAddress) throws Exception {
        // ERC20 symbol() 函数调用
        Function function = new Function(
                "symbol",
                Collections.emptyList(),
                Arrays.asList(new TypeReference<Utf8String>() {})
        );
        
        String encodedFunction = FunctionEncoder.encode(function);
        EthCall response = web3j.ethCall(
                Transaction.createEthCallTransaction(null, tokenAddress, encodedFunction),
                DefaultBlockParameterName.LATEST)
                .send();
        
        List<Type> result = FunctionReturnDecoder.decode(
                response.getValue(), function.getOutputParameters());
        
        return result.isEmpty() ? "" : ((Utf8String) result.get(0)).getValue();
    }
    
    @Override
    public BigInteger getTokenDecimals(String tokenAddress) throws Exception {
        // ERC20 decimals() 函数调用
        Function function = new Function(
                "decimals",
                Collections.emptyList(),
                Arrays.asList(new TypeReference<Uint256>() {})
        );
        
        String encodedFunction = FunctionEncoder.encode(function);
        EthCall response = web3j.ethCall(
                Transaction.createEthCallTransaction(null, tokenAddress, encodedFunction),
                DefaultBlockParameterName.LATEST)
                .send();
        
        List<Type> result = FunctionReturnDecoder.decode(
                response.getValue(), function.getOutputParameters());
        
        return result.isEmpty() ? BigInteger.ZERO : ((Uint256) result.get(0)).getValue();
    }
    
    @Override
    public BigInteger getTokenTotalSupply(String tokenAddress) throws Exception {
        // ERC20 totalSupply() 函数调用
        Function function = new Function(
                "totalSupply",
                Collections.emptyList(),
                Arrays.asList(new TypeReference<Uint256>() {})
        );
        
        String encodedFunction = FunctionEncoder.encode(function);
        EthCall response = web3j.ethCall(
                Transaction.createEthCallTransaction(null, tokenAddress, encodedFunction),
                DefaultBlockParameterName.LATEST)
                .send();
        
        List<Type> result = FunctionReturnDecoder.decode(
                response.getValue(), function.getOutputParameters());
        
        return result.isEmpty() ? BigInteger.ZERO : ((Uint256) result.get(0)).getValue();
    }
    
    @Override
    public BigInteger getTokenBalance(String tokenAddress, String address) throws Exception {
        // ERC20 balanceOf(address) 函数调用
        Function function = new Function(
                "balanceOf",
                Arrays.asList(new org.web3j.abi.datatypes.Address(address)),
                Arrays.asList(new TypeReference<Uint256>() {})
        );
        
        String encodedFunction = FunctionEncoder.encode(function);
        EthCall response = web3j.ethCall(
                Transaction.createEthCallTransaction(null, tokenAddress, encodedFunction),
                DefaultBlockParameterName.LATEST)
                .send();
        
        List<Type> result = FunctionReturnDecoder.decode(
                response.getValue(), function.getOutputParameters());
        
        return result.isEmpty() ? BigInteger.ZERO : ((Uint256) result.get(0)).getValue();
    }
    
    @Override
    public Map<String, Object> getTokenFullInfo(String tokenAddress) throws Exception {
        Map<String, Object> tokenInfo = new HashMap<>();
        
        // 获取代币基本信息
        tokenInfo.put("name", getTokenName(tokenAddress));
        tokenInfo.put("symbol", getTokenSymbol(tokenAddress));
        tokenInfo.put("decimals", getTokenDecimals(tokenAddress));
        tokenInfo.put("totalSupply", getTokenTotalSupply(tokenAddress));
        
        return tokenInfo;
    }
}